/*
 * LPUART.c              Copyright NXP 2016
 * Description: LPUART functions
 * 2015 Sept 28 Kushal Shaw - original version AN5213;
 * 2016 Mar 17  O Romero - ported to S32K144;
 *
 */
#include "main.h"
#include "S32K146.h" /* include peripheral declarations S32K144 */
#include "LPUART.h"

void LPUART1_PORT_init (void) {
  PCC->PCCn[PCC_PORTC_INDEX ]|=PCC_PCCn_CGC_MASK; /* Enable clock for PORTC */
  PORTC->PCR[9]|=PORT_PCR_MUX(2);           /* Port C9: MUX = ALT2,UART1 TX */
  PORTC->PCR[8]|=PORT_PCR_MUX(2);           /* Port C8: MUX = ALT2,UART1 RX */
}

void LPUART1_init(void)  /* Init. summary: 9600 baud, 1 stop bit, 8 bit format, no parity */
{
  PCC->PCCn[PCC_LPUART1_INDEX] &= ~PCC_PCCn_CGC_MASK;    /* Ensure clk disabled for config */
  PCC->PCCn[PCC_LPUART1_INDEX] |= PCC_PCCn_PCS(1)    /* Clock Src= 1 (SOSCDIV2_CLK) */
                               |  PCC_PCCn_CGC_MASK;     /* Enable clock for LPUART1 regs */
  //LPUART1->BAUD = 0x0F000034;  /* Initialize for 9600 baud, 1 stop: */
                               /* TDMAE, RDMAE, TDMAE=0: DMA requests disabled */
  LPUART1->BAUD = 0x0FA00034;  /* Initialize for 9600 baud, 1 stop: */
                               /* SBR=52 (0x34): baud divisor = 8M/9600/16 = ~52 */
                               /* OSR=15: Over sampling ratio = 15+1=16 */
                               /* SBNS=0: One stop bit */
                               /* BOTHEDGE=0: receiver samples only on rising edge */
                               /* M10=0: Rx and Tx use 7 to 9 bit data characters */
                               /* RESYNCDIS=0: Resync during rec'd data word supported */
                               /* LBKDIE, RXEDGIE=0: interrupts disable */
                               /* RDMAE=1, TDMAE=1: RX and TX DMA requests enabled */
                               /* MAEN1, MAEN2,  MATCFG=0: Match disabled */
  //LPUART1->CTRL=0x000C0000;  /* LOOPS=0,RSRC=0: no loop back */
  LPUART1->CTRL=0x000C0080;    /* Enable transmitter & receiver, no parity, 8 bit char: */
                               /* RE=1: Receiver enabled */
                               /* TE=1: Transmitter enabled */
                               /* PE,PT=0: No hw parity generation or checking */
                               /* M7,M,R8T9,R9T8=0: 8-bit data characters*/
                               /* DOZEEN=0: LPUART enabled in Doze mode */
                               /* ORIE,NEIE,FEIE,PEIE,TIE,TCIE,RIE,ILIE,MA1IE,MA2IE=0: no IRQ*/
                               /* TxDIR=0: TxD pin is input if in single-wire mode */
                               /* TXINV=0: TRansmit data not inverted */
                               /* RWU,WAKE=0: normal operation; rcvr not in statndby */
                               /* IDLCFG=0: one idle character */
                               /* ILT=0: Idle char bit count starts after start bit */
                               /* SBK=0: Normal transmitter operation - no break char */
                               /* LOOPS=1,RSRC=0: no loop back */
  LPUART1->FIFO=0x00000099;
  //LPUART1->WATER=0x00030000;
}

void LPUART1_transmit_char(char send) {    /* Function to Transmit single Char */
  while((LPUART1->STAT & LPUART_STAT_TDRE_MASK)>>LPUART_STAT_TDRE_SHIFT==0);
                                   /* Wait for transmit buffer to be empty */
  LPUART1->DATA=send;              /* Send data */
}

void LPUART1_transmit_string(char data_string[])  {  /* Function to Transmit whole string */
  uint32_t i=0;
  while(data_string[i] != '\0')  {           /* Send chars one at a time */
    LPUART1_transmit_char(data_string[i]);
    i++;
  }
}

char LPUART1_receive_char(void) {    /* Function to Receive single Char */
  char recieve;
  if((LPUART1->STAT & LPUART_STAT_RDRF_MASK)>>LPUART_STAT_RDRF_SHIFT==0){
    return 0;
  };
                                     /* Wait for received buffer to be full */
  recieve= LPUART1->DATA;            /* Read received data*/
  return recieve;
}

char rxbuff[256]={0};
uint8_t idx=0;
void LPUART1_receive_and_echo_char(void)  {  /* Function to echo received char back */
  char send = LPUART1_receive_char();        /* Receive Char */
  if(send==0)
    return;
  rxbuff[idx++]=send;
  //LPUART1_transmit_char(send);               /* Transmit same char back to the sender */
  //LPUART1_transmit_char('\n');               /* New line */
  //LPUART1_transmit_char('\r');               /* Return */
}

char data=0;
uint8_t  TransData[] = {"\n\rHello World from TIC!\n\r"}; /* Transmit string & CR*/
uint8_t rxdata[4];


void InitRXDMA(uint32_t *pdst, uint32_t dst_length)
{

  //PCC->PCCn[PCC_DMA0_INDEX] |= PCC_PCCn_CGC_MASK;          	// CGC=1: Clock enabled for DMA0

  DMA->TCD[DMA_CH8].CSR &= 0xFFFFFFFF ^ DMA_TCD_CSR_DONE_MASK;  					// Clear Channel Done flag
  DMA->TCD[DMA_CH8].SADDR = DMA_TCD_SADDR_SADDR(&(LPUART1->DATA));  				// Source Address
  DMA->TCD[DMA_CH8].SOFF = DMA_TCD_SOFF_SOFF(0);                					// Source Offset
  DMA->TCD[DMA_CH8].ATTR = DMA_TCD_ATTR_SMOD(0)  |              					// Source address modulo feature is disabled
                    DMA_TCD_ATTR_SSIZE(0) |              					// Source data transfer size: 0: 8-bit, 1: 16-bit, 2=32-bit
                    DMA_TCD_ATTR_DMOD(0)  |              					// Destination address modulo feature: 0=disabled, x= x power of 2 buffer[DMOD=4->buffer of 16bytes]
                    DMA_TCD_ATTR_DSIZE(0);               					// Destination data transfer size: 0: 8-bit, 1: 16-bit, 2=32-bit
  DMA->TCD[DMA_CH8].NBYTES.MLOFFNO = DMA_TCD_NBYTES_MLNO_NBYTES(1); 				// Minor Byte Transfer Count is 1-byte
  DMA->TCD[DMA_CH8].SLAST = DMA_TCD_SLAST_SLAST(0);             					// Last Source Address Adjustment is 0
  DMA->TCD[DMA_CH8].DADDR = DMA_TCD_DADDR_DADDR(pdst);     						// Destination Address of Buffer
  DMA->TCD[DMA_CH8].DOFF = DMA_TCD_DOFF_DOFF(1);                					// Destination Address Signed Offset is 0
  DMA->TCD[DMA_CH8].CITER.ELINKNO = DMA_TCD_CITER_ELINKNO_CITER(dst_length)  				// Current Major Iteration Count is dst_length
                                     | DMA_TCD_CITER_ELINKNO_ELINK(0);  	// The channel-to-channel linking is disabled
  DMA->TCD[DMA_CH8].DLASTSGA = -dst_length;    					// Destination last address adjustment is 0
  DMA->TCD[DMA_CH8].BITER.ELINKNO = DMA_TCD_BITER_ELINKNO_BITER(dst_length) | 				// Starting major iteration count is dst_length
                                       DMA_TCD_BITER_ELINKNO_ELINK(0);  	// The minor channel-to-channel linking is disabled
  DMA->TCD[DMA_CH8].CSR = DMA_TCD_CSR_BWC(0)         |         					// BWC=0: No eDMA engine stalls - full bandwidth
                    DMA_TCD_CSR_MAJORELINK(0)  |        					// The channel-to-channel linking is disabled
                    DMA_TCD_CSR_MAJORLINKCH(0) |       						// channel 1 will be called from ch0
                    DMA_TCD_CSR_ESG(0)         |         					// The current channel?fs TCD is normal format - No scatter/gather
                    DMA_TCD_CSR_DREQ(0)        |         					// The channel's ERQ bit is not affected
                    DMA_TCD_CSR_INTHALF(0)     |         					// The half-point interrupt is disabled
                    DMA_TCD_CSR_INTMAJOR(1)    |         					// The end-of-major loop interrupt is enabled
                    DMA_TCD_CSR_START(0);                					// The channel is not explicitly started

  DMA->SERQ = DMA_CH8;	// enable DMA channel 0 HW trigger
  
	S32_NVIC->ICPR[0] = 1 << (DMA8_IRQn % 32);  /* IRQ12-DMA ch12: clr any pending IRQ*/
	S32_NVIC->ISER[0] = 1 << (DMA8_IRQn % 32);  /* IRQ12-DMA ch12: enable IRQ */
 	S32_NVIC->IP[DMA8_IRQn] = 0xA;              /* IRQ12-DMA ch12: priority 10 of 0-15*/
}

void InitTXDMA(uint32_t *psrc, uint32_t src_length)
{

  //PCC->PCCn[PCC_DMA0_INDEX] |= PCC_PCCn_CGC_MASK;          	// CGC=1: Clock enabled for DMA0

  DMA->TCD[DMA_CH9].CSR &= 0xFFFFFFFF ^ DMA_TCD_CSR_DONE_MASK;  					// Clear Channel Done flag
  DMA->TCD[DMA_CH9].SADDR = DMA_TCD_SADDR_SADDR(psrc);  				// Source Address
  DMA->TCD[DMA_CH9].SOFF = DMA_TCD_SOFF_SOFF(1);                					// Source Offset
  DMA->TCD[DMA_CH9].ATTR = DMA_TCD_ATTR_SMOD(0)  |              					// Source address modulo feature is disabled
                    DMA_TCD_ATTR_SSIZE(0) |              					// Source data transfer size: 0: 8-bit, 1: 16-bit, 2=32-bit
                    DMA_TCD_ATTR_DMOD(0)  |              					// Destination address modulo feature: 0=disabled, x= x power of 2 buffer[DMOD=4->buffer of 16bytes]
                    DMA_TCD_ATTR_DSIZE(0);               					// Destination data transfer size: 0: 8-bit, 1: 16-bit, 2=32-bit
  DMA->TCD[DMA_CH9].NBYTES.MLOFFNO = DMA_TCD_NBYTES_MLNO_NBYTES(1); 				// Minor Byte Transfer Count is 1-byte
  DMA->TCD[DMA_CH9].SLAST = -src_length;             					// Last Source Address Adjustment is 0
  DMA->TCD[DMA_CH9].DADDR = DMA_TCD_DADDR_DADDR(&(LPUART1->DATA));     						// Destination Address
  DMA->TCD[DMA_CH9].DOFF = DMA_TCD_DOFF_DOFF(0);                					// Destination Address Signed Offset is 0
  DMA->TCD[DMA_CH9].CITER.ELINKNO = DMA_TCD_CITER_ELINKNO_CITER(src_length)  				// Current Major Iteration Count is dst_length
                                     | DMA_TCD_CITER_ELINKNO_ELINK(0);  	// The channel-to-channel linking is disabled
  DMA->TCD[DMA_CH9].DLASTSGA = DMA_TCD_DLASTSGA_DLASTSGA(0);    					// Destination last address adjustment is 0
  DMA->TCD[DMA_CH9].BITER.ELINKNO = DMA_TCD_BITER_ELINKNO_BITER(src_length) | 				// Starting major iteration count is dst_length
                                       DMA_TCD_BITER_ELINKNO_ELINK(0);  	// The minor channel-to-channel linking is disabled
  DMA->TCD[DMA_CH9].CSR = DMA_TCD_CSR_BWC(0)         |         					// BWC=0: No eDMA engine stalls - full bandwidth
                    DMA_TCD_CSR_MAJORELINK(0)  |        					// The channel-to-channel linking is disabled
                    DMA_TCD_CSR_MAJORLINKCH(0) |       						// channel 1 will be called from ch0
                    DMA_TCD_CSR_ESG(0)         |         					// The current channel?fs TCD is normal format - No scatter/gather
                    DMA_TCD_CSR_DREQ(1)        |         					// The channel's ERQ bit is affected
                    DMA_TCD_CSR_INTHALF(0)     |         					// The half-point interrupt is disabled
                    DMA_TCD_CSR_INTMAJOR(1)    |         					// The end-of-major loop interrupt is enabled
                    DMA_TCD_CSR_START(0);                					// The channel is not explicitly started

  DMA->SERQ = DMA_CH9;	// enable DMA channel 1 HW trigger
  
	S32_NVIC->ICPR[0] = 1 << (DMA9_IRQn % 32);  /* IRQ12-DMA ch12: clr any pending IRQ*/
	S32_NVIC->ISER[0] = 1 << (DMA9_IRQn % 32);  /* IRQ12-DMA ch12: enable IRQ */
 	S32_NVIC->IP[DMA9_IRQn] = 0xA;              /* IRQ12-DMA ch12: priority 10 of 0-15*/
}

void LPUART_DMAMUX_Init (void)
{
    PCC->PCCn[PCC_DMAMUX_INDEX] |= PCC_PCCn_CGC_MASK;    // CGC=1: Clock enabled for DMAMUX0

    DMAMUX->CHCFG[DMA_CH8] &= ~ DMAMUX_CHCFG_ENBL(1);         // Disabling the DMA channel
    DMAMUX->CHCFG[DMA_CH8] |= DMAMUX_CHCFG_SOURCE(4);        // LPUART1 RX is the source of the DMA0 channel
    DMAMUX->CHCFG[DMA_CH8] |= DMAMUX_CHCFG_ENBL(1);           // Enabling the DMA channel

    DMAMUX->CHCFG[DMA_CH9] &= ~ DMAMUX_CHCFG_ENBL(1);         // Disabling the DMA channel
    DMAMUX->CHCFG[DMA_CH9] |= DMAMUX_CHCFG_SOURCE(5);        // LPUART1 TX is the source of the DMA0 channel
    DMAMUX->CHCFG[DMA_CH9] |= DMAMUX_CHCFG_ENBL(1);           // Enabling the DMA channel
}

void LPUART_TEST_Poll_Init()
{
    PORT_init();           /* Configure ports */

    LPUART1_init();        /* Initialize LPUART @ 9600*/
    //LPUART1_transmit_string("Running LPUART example\n\r");     /* Transmit char string */
    //LPUART1_transmit_string("Input character to echo...\n\r"); /* Transmit char string */
}

void LPUART_TEST_Poll_Main()
{
    LPUART1_transmit_char('H');       /* Transmit prompt character*/
    //LPUART1_receive_and_echo_char();  /* Wait for input char, receive & echo it*/
}

void LPUART_TEST_Dma_Init()
{
    PORT_init();           /* Configure ports */
    LPUART_DMAMUX_Init();

    LPUART1_init();        /* Initialize LPUART @ 9600*/
    InitTXDMA((uint32_t *)&TransData[0],sizeof(TransData)); // Init TCD to send a string
    DMA->SERQ = DMA_CH9;    // enable DMA channel 1 HW trigger
    
    //while(!(DMA->TCD[DMA_CH9].CSR & DMA_TCD_CSR_DONE_MASK) ){}; // wait until the string is sent

    InitTXDMA((uint32_t *)&rxdata,sizeof(rxdata)); // Init a TCD to send just 4 bytes (size of rxdata)
    InitRXDMA((uint32_t *)&rxdata,sizeof(rxdata)); // Init a TCD to receive just 4 bytes
}

void LPUART_TEST_Dma_Main()
{
   while(!(DMA->TCD[DMA_CH9].CSR & DMA_TCD_CSR_DONE_MASK) ){}; // wait until the string is sent

   if(DMA->INT == 0x1)    // if received 4 bytes
   {
       DMA->SERQ = 1; // enable DMA channel 1 HW trigger to send 4 bytes back
       DMA->INT = 0x1;    // clear channel 0
   }
    

}


